package cn.tedu.tmall.front.mall.dao.repository.impl;

import cn.tedu.tmall.front.mall.dao.repository.ICartCacheRepository;
import cn.tedu.tmall.front.mall.pojo.po.CartPO;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.HashOperations;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Repository;
import org.springframework.util.CollectionUtils;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

@Slf4j
@Repository
public class CartCacheRepository implements ICartCacheRepository {

    private final String CART_KEY = "mall_cart_";

    @Autowired
    private RedisTemplate<String, Serializable> redisTemplate;

    /**
     * // redis
     *         // 用哪个结构
     *         //  zset ? score 来表示商品数量,增加或者减少 减少score
     *         //  hash !!!  独享 一个人一个购物车
     *         //  大key mall_cart_user_id
     *         //  小key 商品id
     *         //   value 商品数量
     * @param userId
     * @param cartPO
     */
    @Override
    public void add(Long userId,CartPO cartPO) {
        log.debug("购物车数据存入缓存:userId-{},购物车数据:{}",userId,cartPO);
        HashOperations<String, Object, Object> hashOperations = redisTemplate.opsForHash();

        //String cartKey = "mall_cart";

        // value 是数量?
        //  商品名称和商品价格如何处理?
        //   new ArrayList 商品名称,商品价格 都放到list
        //List<Object> cartInfo = new ArrayList<>();
        //cartInfo.add(cartPO.getGoodsName());
        //cartInfo.add(cartPO.getGoodsNum());
        //我们思考怎么放的时候,要思考将来怎么取?或者怎么用
        //
        // 1 我要给一个商品增加数量 ,你怎么增?
        // 商品id 11 num 99
        // 我们直接增加相同的商品id的时候通过put会覆盖 bug
        // 能用
        //先把过去的取出来,然后把入参的和过去进行合并 然后在放到redis
        // 两条命令

        //通过用户id获取大key
        String cartKey = getCartKey(userId);
        // 商品id 多个商品
        Long hashKey = cartPO.getGoodsId();

        //商品数量小key 需要修改
        String numHashKey = getGoodsNumHashKey(hashKey);
        //商品是否选中小key 需要修改
        String checkHashKey = getGoodsCheckedHashKey(hashKey);
        //商品基本信息小key 不需要修改的数据 商品名称 商品价格
        String goodsHashKey = getGoodsInfoHashKey(hashKey);
        Map<String,Object> smallMap = new HashMap<>();
        smallMap.put(numHashKey,cartPO.getGoodsNum());
        smallMap.put(checkHashKey,cartPO.getChecked());
        smallMap.put(goodsHashKey,cartPO);
        hashOperations.putAll(cartKey,smallMap);

        //一条搞定
        //String numHashKey = cartPO.getGoodsId() + "_num";
        //hashOperations.put(cartKey,numHashKey,cartPO.getGoodsNum());
        //hashOperations.increment(cartKey,numHashKey,2);

        /*Map<String, Map<String,Object>> map = new HashMap<>();
        Map<String,Object> smallMap = new HashMap<>();
        smallMap.put("商品id","购物车数据");
        map.put("userId",smallMap);

        */
        //一个命令搞定
        //hashOperations.increment(cartKey,numHashKey,2);


    }

    private String getGoodsNumHashKey(Long hashKey) {
        return hashKey + "_num";
    }
    private String getGoodsCheckedHashKey(Long hashKey) {
        return hashKey + "_checked";
    }
    private String getGoodsInfoHashKey(Long hashKey) {
        return hashKey + "_goods";
    }

    @Override
    public CartPO getGoodsByUserIdAndGoodsId(Long userId, Long goodsId) {
        HashOperations<String, String, CartPO> hashOperations = redisTemplate.opsForHash();
        String cartKey  = getCartKey(userId);
        //昨天我们的结构
        //String hashKey = goodsId + ""
        String goodsHashKey = goodsId + "_goods";
        CartPO cartPO = hashOperations.get(cartKey, goodsHashKey);
        return cartPO;
    }

    /**
     *
     * 更新数据实现方法B
     * 拆分为多个小key
     * goods_num  商品id_数量
     * goods_checked  商品id_是否选中
     *
     *  Map<String,Object> newSmallMap = new HashMap<>();
     *         smallMap.put("goods_num","商品数量");
     *         smallMap.put("goods_checked","商品是否选中");
     *         smallMap.put("商品id_价格","购物车数据的价格");
     *         map.put("userId",newSmallMap);
     * @param userId
     * @param goodsId
     * @param goodsNum
     */
    @Override
    public void addCartGoodsNum(Long userId, Long goodsId, Integer goodsNum) {
        HashOperations<String, String, CartPO> hashOperations = redisTemplate.opsForHash();
        String cartKey  = getCartKey(userId);
        String numHashKey = getGoodsNumHashKey(goodsId);
        hashOperations.increment(cartKey,numHashKey,goodsNum);
    }

    @Override
    public List<CartPO> list(Long userId) {
        HashOperations<String, String, Object> hashOperations = redisTemplate.opsForHash();
        //这个是大key mall_cart_用户id
        String cartKey = getCartKey(userId);
        //1 一次 通过大key全部查询,用程序来过滤
        //所有商品信息
        List<CartPO> result = new ArrayList<>();
        //通过大key获取所有数据
        Map<String, Object> entries = hashOperations.entries(cartKey);
        //判断数据是否为空
        if (!CollectionUtils.isEmpty(entries)) {
            //遍历所有数据,过滤出商品信息
            // 商品id_goods 保存的商品信息
            //过滤条件是 hash_key 是否包含 goods
            entries.forEach((k,v) ->{
                if (k.contains("goods")) {
                    //商品信息
                    CartPO currentCartPo = (CartPO)v;
                    //放到所有商品信息的list
                    result.add(currentCartPo);
                }
            });
            //过滤商品信息
            result.forEach(po ->{
                //取出商品id
                Long goodsId = po.getGoodsId();
                //拼接商品数量的hash_key 商品id_num
                String goodsNumHashKey = getGoodsNumHashKey(goodsId);
                //从大key对应的所有数据里获取商品数量
                Object goodsNum = entries.get(goodsNumHashKey);
                //把商品数量转换为Integer并且设置到商品信息
                po.setGoodsNum(Integer.valueOf(String.valueOf(goodsNum)));
                //拼接商品选择状态的hash_key 商品id_checked
                String goodsCheckedHashKey = getGoodsCheckedHashKey(goodsId);
                //从大key对应的所有数据里获取商品选中状态
                Object goodsChecked = entries.get(goodsCheckedHashKey);
                //把商品是否选中转换为Integer并且设置到商品信息
                po.setChecked(Integer.valueOf(String.valueOf(goodsChecked)));
            });
        }
        log.debug("一次查询所有购物车数据,用户id:{},购物车数据:{}",userId,entries);
        //2 多次 先把hashkey 查出来,然后通过hashkey 查具体的值
        log.debug("购物车数据转化为PO后的结果:{}",result);
        return result;
    }

    @Override
    public void delByUserIdAndGoodsId(Long userId, Long goodsId) {
        HashOperations<String, String, Object> hashOperations = redisTemplate.opsForHash();
        String cartKey = getCartKey(userId);
        //商品id_num
        String goodsNumHashKey = getGoodsNumHashKey(goodsId);
        //商品id_checked
        String goodsCheckedHashKey = getGoodsCheckedHashKey(goodsId);
        //商品id_goods
        String goodsInfoHashKey = getGoodsInfoHashKey(goodsId);
        hashOperations.delete(cartKey,goodsNumHashKey,
                goodsCheckedHashKey,goodsInfoHashKey);
    }

    @Override
    public void modify(Long userId, Long goodsId, Integer goodsNum) {
        String cartKey = getCartKey(userId);
        //商品id_num
        String goodsNumHashKey = getGoodsNumHashKey(goodsId);
        HashOperations<String, String, Object> hashOperations = redisTemplate.opsForHash();
        //put 操作 没有就添加 有就覆盖 ,选中,取消选中可以采用同一种方法,但是需要注意小key不同
        hashOperations.put(cartKey,goodsNumHashKey,goodsNum);
    }

    @Override
    public void updateCheckStatusByUserIdAndGoodsId(Long userId, Long goodsId, Integer checkStatus) {
        HashOperations<String, String, Object> hashOperations = redisTemplate.opsForHash();
        String cartKey = getCartKey(userId);
        String goodsCheckedHashKey = getGoodsCheckedHashKey(goodsId);
        //先获取到选中状态,
        // 把值替换
        hashOperations.put(cartKey,goodsCheckedHashKey,checkStatus);
    }

    /**
     * 生成大key
     * @param userId
     * @return
     */
    private String getCartKey(Long userId){
        return CART_KEY + userId;
    }

    /**
     * 更新数据实现方法A
     * 1 现通过大key获取出商品的全部数据
     * 2 然后更新值
     * 3 然后保存
     *  Map<String,Object> smallMap = new HashMap<>();
     *         smallMap.put("商品id","购物车数据");
     *         map.put("userId",smallMap);
     *
     */
    private void add(){
        /*String cartKey  = getCartKey(userId); //todo 这么写没问题
        Object oldCart = hashOperations.get(cartKey, hashKey);
        if (oldCart != null) {
            CartPO oldCartPO = (CartPO) oldCart;
            Integer oldGoodsNum = oldCartPO.getGoodsNum();
            Integer newGoodsNum = cartPO.getGoodsNum();
            Integer currentGoodNum = oldGoodsNum + newGoodsNum;
            cartPO.setGoodsNum(currentGoodNum);
        }
        hashOperations.put(CART_KEY,hashKey,cartPO);*/
    }
}
